{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Sweeps - Capacitance matrix"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Prerequisite\n",
    "You need to have a working local installation of Ansys"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Perform the necessary imports and create a QDesign in Metal first."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%load_ext autoreload\n",
    "%autoreload 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import qiskit_metal as metal\n",
    "from qiskit_metal import designs, draw\n",
    "from qiskit_metal import MetalGUI, Dict, Headings\n",
    "from qiskit_metal.analyses.quantization import LOManalysis\n",
    "from qiskit_metal.renderers.renderer_ansys.ansys_renderer import QAnsysRenderer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "design = designs.DesignPlanar()\n",
    "gui = MetalGUI(design)\n",
    "\n",
    "from qiskit_metal.qlibrary.qubits.transmon_pocket import TransmonPocket"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "design.variables['cpw_width'] = '15 um'\n",
    "design.variables['cpw_gap'] = '9 um'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### In this example, the design consists of 4 qubits and 4 CPWs."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Allow running the same cell here multiple times to overwrite changes\n",
    "design.overwrite_enabled = True\n",
    "\n",
    "## Custom options for all the transmons\n",
    "options = dict(\n",
    "    # Some options we want to modify from the defaults\n",
    "    # (see below for defaults)\n",
    "    pad_width = '425 um', \n",
    "    pocket_height = '650um',\n",
    "    # Adding 4 connectors (see below for defaults)\n",
    "    connection_pads=dict(\n",
    "        readout = dict(loc_W=+1,loc_H=-1, pad_width='200um'),\n",
    "        bus1 = dict(loc_W=-1,loc_H=+1, pad_height='30um'),\n",
    "        bus2 = dict(loc_W=-1,loc_H=-1, pad_height='50um')\n",
    "    )\n",
    ")\n",
    "\n",
    "## Create 4 transmons\n",
    "\n",
    "q1 = TransmonPocket(design, 'Q1', options = dict(\n",
    "    pos_x='+2.42251mm', pos_y='+0.0mm', **options))\n",
    "q2 = TransmonPocket(design, 'Q2', options = dict(\n",
    "    pos_x='+0.0mm', pos_y='-0.95mm', orientation = '270', **options))\n",
    "q3 = TransmonPocket(design, 'Q3', options = dict(\n",
    "    pos_x='-2.42251mm', pos_y='+0.0mm', orientation = '180', **options))\n",
    "q4 = TransmonPocket(design, 'Q4', options = dict(\n",
    "    pos_x='+0.0mm', pos_y='+0.95mm', orientation = '90', **options))\n",
    "\n",
    "from qiskit_metal.qlibrary.tlines.meandered import RouteMeander\n",
    "RouteMeander.get_template_options(design)\n",
    "\n",
    "options = Dict(\n",
    "        lead=Dict(\n",
    "            start_straight='0.2mm',\n",
    "            end_straight='0.2mm'),\n",
    "        trace_gap='9um',\n",
    "        trace_width='15um')\n",
    "\n",
    "def connect(component_name: str, component1: str, pin1: str, component2: str, pin2: str,\n",
    "            length: str, asymmetry='0 um', flip=False, fillet='90um'):\n",
    "    \"\"\"Connect two pins with a CPW.\"\"\"\n",
    "    myoptions = Dict(\n",
    "        fillet=fillet,\n",
    "        hfss_wire_bonds = True,\n",
    "        pin_inputs=Dict(\n",
    "            start_pin=Dict(\n",
    "                component=component1,\n",
    "                pin=pin1),\n",
    "            end_pin=Dict(\n",
    "                component=component2,\n",
    "                pin=pin2)),\n",
    "        total_length=length)\n",
    "    myoptions.update(options)\n",
    "    myoptions.meander.asymmetry = asymmetry\n",
    "    myoptions.meander.lead_direction_inverted = 'true' if flip else 'false'\n",
    "    return RouteMeander(design, component_name, myoptions)\n",
    "\n",
    "asym = 140\n",
    "cpw1 = connect('cpw1', 'Q1', 'bus2', 'Q2', 'bus1', '5.6 mm', f'+{asym}um')\n",
    "cpw2 = connect('cpw2', 'Q3', 'bus1', 'Q2', 'bus2', '5.7 mm', f'-{asym}um', flip=True)\n",
    "cpw3 = connect('cpw3', 'Q3', 'bus2', 'Q4', 'bus1', '5.6 mm', f'+{asym}um')\n",
    "cpw4 = connect('cpw4', 'Q1', 'bus1', 'Q4', 'bus2', '5.7 mm', f'-{asym}um', flip=True)\n",
    "\n",
    "gui.rebuild()\n",
    "gui.autoscale()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2 Metal passes information to the simulator \"q3d\" to extract the capacitance matrix.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "c1 = LOManalysis(design, \"q3d\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Prepare data to pass as arguments for method run_sweep()."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "render_design_argument_qcomps = ['Q1']\n",
    "\n",
    "render_design_argument_endcaps = [('Q1', 'readout'), ('Q1', 'bus1'),('Q1', 'bus2')]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# To identify the agruments that you can change.\n",
    "# They will change based on the simulation software used.\n",
    "c1.sim.setup"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# For the simulation software, if you don't want to use the default values, \n",
    "# you can update them as seen below.\n",
    "\n",
    "# If a setup named \"sweeper_q3d_setup\" exists in the project, it will be deleted, \n",
    "# and a new setup will be added.\n",
    "c1.sim.setup.name = \"sweeper_q3d_setup\"\n",
    "\n",
    "c1.sim.setup.freq_ghz = 5.6\n",
    "c1.sim.setup.max_passes = 9\n",
    "c1.sim.setup.min_passes = 2\n",
    "c1.sim.setup.percent_error = 0.45"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "We will look at modifying the pad_gap of qubit 1, to see how it impacts the anharmonicity of the qubit.\n",
    "\n",
    "The steps will be;\n",
    "- Connect to Ansys Q3D.\n",
    "- Rebuild QComponents in Metal.\n",
    "- Render QComponents within Q3D and setup the simulation.\n",
    "- Delete/Clear the Q3D between each simulation.\n",
    "- Using the capacitance matrices, LOM for each value in option_sweep is found.\n",
    "\n",
    "#### Returns a dict and return code.  If the return code is zero, there were no errors detected.  \n",
    "#### The dict has:  key = each value used to sweep, value = capacitance matrix\n",
    "\n",
    "#### This could take minutes or hours based on the complexity of the design.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sweep_data, return_code = c1.run_sweep(q1.name,\n",
    "                                       'pad_gap',\n",
    "                                       ['20um', '30um', '40um'],\n",
    "                                       render_design_argument_qcomps,\n",
    "                                       render_design_argument_endcaps,\n",
    "                                       design_name=\"GetCapacitance\",\n",
    "                                       box_plus_buffer=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pandas import DataFrame\n",
    "\n",
    "ec_val = []\n",
    "for opt_val in sweep_data.keys():\n",
    "    ec_val.append([opt_val,sweep_data[opt_val]['variables']['lumped_oscillator']['EC']])\n",
    "\n",
    "df=DataFrame(ec_val,columns = ['Sweep Value', 'Ec'])\n",
    "df"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can grab specific values from the results as seen below;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sweep_data.keys()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# For each value of option, there is a set of data.\n",
    "sweep_data['20um'].keys()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sweep_data['20um']['variables'].keys()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sweep_data['20um']['sim_variables'].keys()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if return_code ==0:\n",
    "    print(f'{sweep_data.keys()} \\n')\n",
    "    for key in sweep_data.keys():\n",
    "        print(f'\\nkey={key}')\n",
    "        \n",
    "        option_name = sweep_data[key]['option_name']\n",
    "        print(f'option_name[\\'{key}\\'][\\'option_name\\']={option_name}')\n",
    "        \n",
    "    \n",
    "        variables = sweep_data[key]['variables']\n",
    "        sim_variables = sweep_data[key]['sim_variables']\n",
    "        \n",
    "        print(f'variables={variables}')\n",
    "        print(f'sim_variables={sim_variables}')\n",
    "        \n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# READ THIS BEFORE running the cell.\n",
    "This cell is to demonstrate that if you have already executed c1.sim.run(), you don't have to set up \n",
    "the environment again for c1.run_sweep().  In another words, if you don't pass updated arguments to\n",
    "c1.run_sweep(), then c1.run_sweep() looks for the previous desgin arguments. \n",
    "\n",
    "If you pass anything more than these three arguments: qcomp_name, option_name, option_sweep ..... \n",
    "Then NOTHING will be used from previous run.  \n",
    "```\n",
    "c1.sim.solution_order = 'Medium'\n",
    "c1.sim.auto_increase_solution_order = 'False'\n",
    "\n",
    "\n",
    "c1.sim.run(components=render_design_argument_qcomps,\n",
    "           open_terminations=render_design_argument_endcaps)\n",
    "```\n",
    "\n",
    "Because c1.sim.setup.run has the information from last run, this is OK.\n",
    "\n",
    "```\n",
    "sweep_data, return_code = c1.run_sweep(q1.name, \n",
    "                                        'pad_gap', \n",
    "                                        ['20um', '30um', '40um'])\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "c1.sim.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Uncomment next line if you would like to close the gui\n",
    "gui.main_window.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
